home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-07-31 | 15.0 KB | 469 lines | [TEXT/MPS ] |
- /*
- File: HWSpecific.c
-
- Contains: This file contains the routine(s) that are hardware specific for the
- DLPI. Each vendor must supply code that works with their own
- card.
-
- Written by:
-
- Copyright: © 1994 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
-
- To Do:
- */
-
- //-----------------------------------------------------------------------------------------
- // Header files
- //-----------------------------------------------------------------------------------------
-
- #include <OpenTptModule.h> // Open Transport files
- #include <OpenTptDevLinks.h>
-
- #include <Interrupts.h> // System files
- #include <PCI.h>
- #include <Kernel.h>
- #include <OSUtils.h>
- #include <DriverServices.h>
-
- #include "PCIRoutines.h" // our files
- #include "DLPIRoutines.h"
- #include "HWSpecific.h"
- #include "EntryPoints.h"
-
- //-----------------------------------------------------------------------------------------
- // Global variable for the entire CFM
- //-----------------------------------------------------------------------------------------
-
- extern DLPIPrivateData *gDLPIPrivateData; // Declared in EntryPoints.c
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine enables our interrupts based on a parameter passed in. Code should
- // be added to this routine that enables the various interrupt bits on the card.
- // The enable and disable routines are used by the queue routines to protect
- // critical code sections. Instead of masking all interrupts we just select
- // the appropriate ones for our card.
- //
- // Input:
- // whichIntsOn - turn which interrupts on transmit, receive, or none
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void ABCVendorEnableInterrupts(UInt16 whichIntsOn)
- {
-
- switch (whichIntsOn)
- {
- case kTxInterrupts:
- // turn on tx interrupts
- break;
- case kRxInterrupts:
- // turn on rx interrupts
- break;
- case kBothTxRxInterrupts:
- // turn on both interrupts
- break;
- default:
- break;
- }
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine disables our interrupts based on a parameter passed in.Code should
- // be added to this routine that disables the various interrupt bits on the card.
- // The enable and disable routines are used by the queue routines to protect
- // critical code sections. Instead of masking all interrupts we just select
- // the appropriate ones for our card.
- //
- // Input:
- // whichIntsOff - turn which interrupts off transmit, receive, or none
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void ABCVendorDisableInterrupts(UInt16 whichIntsOff)
- {
-
- switch (whichIntsOff)
- {
- case kTxInterrupts:
- // turn off tx interrupts
- break;
- case kRxInterrupts:
- // turn off rx interrupts
- break;
- case kBothTxRxInterrupts:
- // turn off both interrupts
- break;
- default:
- break;
- }
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine should determine if the card pointed to by theID can be used
- // by this driver. Before we can talk to the card, the card must be enabled. To
- // enable the card use the Expansion Manager calls to "set" the appropriate
- // address space bit for your card.
- //
- // Always turn off the card after the test has been made. Just because this routine
- // is executed, it does not mean that the card is going to be used by the system.
- //
- // Input:
- // theID - NameRegistry ID of our pci card
- // resgisterSetAddress - base address of our pci card
- //
- // Output:
- // returns true, if driver can work with the card
- // returns false, if driver cannot work with the card
- //
- //-----------------------------------------------------------------------------------------
- Boolean ABCVendorIsThisOurCard(RegEntryID *theID, UInt32 resgisterSetAddress)
- {
- UInt16 commandValue, newCommandValue, readValue;
- OSErr error;
-
- error = ExpMgrConfigReadWord(theID, kPCIConfigCommandRegister,&commandValue);
- newCommandValue = commandValue | kIOSpaceEnableBit; // turn on the card i/o space
- error = ExpMgrConfigWriteWord(theID, kPCIConfigCommandRegister, newCommandValue);
-
- // CARD REGISTERS ARE NOW ACCESSIBLE!
-
- // Remember that the card is little endian and the processor is big endian.
- // Long words (32 bits) and words (16 bits) must be swapped.
-
- // readValue = *((UInt16 *)(resgisterSetAddress + offset to your register));
-
- // turn card back off
- error = ExpMgrConfigWriteWord(theID, kPCIConfigCommandRegister, commandValue);
-
- return kTrue;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine should set the physical address in the ethernet hw. On initialization
- // we may have read our physical address out of a EPROM, but now somebody is
- // explicitly telling us to change our address. Update in globals.
- //
- // Input:
- // physicalAddress - multicast address (array of 6 bytes)
- //
- // Output:
- // returns no error
- //
- //-----------------------------------------------------------------------------------------
- SInt32 ABCVendorSetEthernetAddress(UInt8 *physicalAddress)
- {
-
- OTCopy48BitAddress(physicalAddress,&gDLPIPrivateData->ourEAddress);
-
- return kOTNoError;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine retrieves the factory ethernet address. This is not the same
- // as the current ethernet physical address (ourEAddress).
- //
- // Input:
- // addressArray - address to place the factory ethernet address bytes
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void ABCVendorGetFactoryEthernetAddress(UInt8 *addressArray)
- {
- SInt16 index;
-
- for (index=0;index != 6;index++)
- {
- addressArray[index] = index; // read factory setting from where ever it is stored
- }
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine enables the hardware to receive a new multicast address. The
- // address has already been verified that it is a multicast address. Another
- // check was made before this routine was called that this address is not a
- // duplicate. All that needs to be done at this point is manipulate the hardware
- // so that it will start receiving packets whose destination is the address.
- //
- // Input:
- // newMulticastAddr - multicast address (array of 6 bytes)
- //
- // Output:
- // returns no error
- //
- //-----------------------------------------------------------------------------------------
- SInt32 ABCVendorRegisterMulticast(UInt8 *newMulticastAddr)
- {
-
- return kOTNoError;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine manipulates the hardware in order to not receive the multicast
- // address. The address was check to see if it had been registered previously.
- // All that needs to be done at this point is manipulate the hardware
- // so that it will stop receiving packets whose destination is the address.
- //
- // Input:
- // oldMulticastAddr - multicast address (array of 6 bytes)
- //
- // Output:
- // returns no error
- //
- //-----------------------------------------------------------------------------------------
- SInt32 ABCVendorUnregisterMulticast(UInt8 *oldMulticastAddr)
- {
-
- return kOTNoError;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine communicates with the transmitter to send the packet described in
- // the message block thePacket. If for some unknown reason you cannot send
- // the packet then drop the packet on the floor.
- //
- // Code in this routine demonstrates how to extract the packet data from the
- // message. This is just a sample, change to fit your hardware. It is currently
- // commented out since the dma memory ptr is not defined.
- //
- // Input:
- // packetSize - byte count of the packet
- // thePacket - message block that describes the packet to transmit
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void ABCVendorTransmitOnePacket(mblk_t *thePacket, UInt16 packetSize)
- {
-
- #if 0
-
- UInt8 *theDMAMemoryPtr; // this copy algorithm
- UInt32 copySize;
-
- while (thePacket)
- {
- copySize = thePacket->b_wptr - thePacket->b_rptr;
-
- bcopy((Ptr)thePacket->b_rptr, theDMAMemoryPtr, copySize);
-
- theDMAMemoryPtr += copySize;
-
- thePacket = thePacket->b_cont;
-
- }
- #endif
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine needs to check the transmitter hw to determine if it can send
- // a packet with a size of packetSize.
- //
- // Input:
- // packetSize - byte count of the packet
- //
- // Output:
- // kOTNoError, if the transmitter hw can handle the packet
- // nonzero, if the transmitter hw cannot handle the packet
- //
- //-----------------------------------------------------------------------------------------
- OSErr ABCVendorCheckTransmitterStatus(UInt16 packetSize)
- {
-
-
-
- return kOTNoError;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine first trys to allocate memory for our gDLPIPrivateData.The
- // hardware should then be initialized. One of the things during the hw initialization
- // that should be done is to read in our Ethernet address.
- // The gDLPIPrivateData global is set in this routine.
- //
- // Input:
- // RegEntryID - NameRegistry ID for our PCI card
- //
- // Output:
- // gDLPIPrivateData, NULL if initialization was not successfull
- // !NULL, if initialization was successfull
- //
- //-----------------------------------------------------------------------------------------
-
- void ABCVendorInitialize(RegEntryID *theID)
- {
- OSStatus osStatus;
- UInt32 amountAllocated;
-
-
- // allocate memory, do not use OT memory unless we need to, OT memory
- // allocation is interrupt safe so lets not waste it when we can use PoolAlocateResident.
- // Thanks to a developer in Sweden for pointing this out!
- gDLPIPrivateData = (DLPIPrivateData *)PoolAllocateResident( sizeof(DLPIPrivateData),kTrue );
- if (gDLPIPrivateData == NULL)
- return;
-
- *(&gDLPIPrivateData->nodeEntryID) = *((RegEntryID *)theID); // copy our reg node id
-
- GetPCICardBaseAddress(&gDLPIPrivateData->nodeEntryID,&gDLPIPrivateData->cardBaseAddr,
- kPCIConfigBase10Offset,&amountAllocated);
-
-
- ABCVendorGetFactoryEthernetAddress(gDLPIPrivateData->ourEAddress);
-
-
- // register interrupt handlers
- osStatus = InstallISR(); // ignore the error right now!
-
- // initialize hardware, remember to turn on the address map bit in the Config Command Register
- // also if the card does dma then you need to turn on the dma (master) bit
-
-
- gDLPIPrivateData->TxDeferredTaskCookie = OTCreateDeferredTask(TxDTCallback,NULL);
- gDLPIPrivateData->RxDeferredTaskCookie = OTCreateDeferredTask(RxDTCallback,NULL);
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine closes down the hardware. The memory is also deallocated.
- // This routine undoes everything done in the initialize routine.
- //
- // Input:
- // NONE
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
-
- void ABCVendorClose(void)
- {
- OSStatus osStatus;
- mblk_t *thePacket;
-
- // turn off hardware
-
- // unregister interrupt handlers
- osStatus = UninstallISR(); // ignore the error right now!
-
-
- OTDestroyDeferredTask(gDLPIPrivateData->TxDeferredTaskCookie);
- OTDestroyDeferredTask(gDLPIPrivateData->RxDeferredTaskCookie);
-
-
- // clear out the tx and rx dlpi private queues
- while ((thePacket = (mblk_t *) DequeueHead(&gDLPIPrivateData->RxPacketQueue, kNoInterrupts))
- != NULL)
- freemsg(thePacket);
-
- while ((thePacket = (mblk_t *) DequeueHead(&gDLPIPrivateData->TxPacketQueue, kNoInterrupts))
- != NULL)
- freemsg(thePacket);
-
- // deallocate memory, must use same routine pair as the allocate
- PoolDeallocate(gDLPIPrivateData);
- gDLPIPrivateData = NULL;
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is the interrupt service routine for our card. Do necessary
- // stuff in isr then defer for a later time the bulk of the work. In the isr
- // you need to notify Open Transport that we are in an isr. The next step
- // is to clear whatever hw bit you need to in order to deassert the interrupt line.
- //
- // For the transmitter...
- // Since the transmitter isr section normally is called after a packet
- // has been transmitted or some error occurs. You need to cleanup anything
- // related to the packet transmission (collect statistics, ...) and then
- // check the TxPacketQueue to see if you have any packets waiting to
- // be sent. If there are packets then schedule the deferred task and when
- // the callback occurs it will try to send any packet waiting on the queue.
- //
- // For the receiver...
- // If this section is called then you need to collect the packet and place
- // it in a message block. The message block can then be placed on the
- // RxPacketQueue. The callback routine which is called after scheduling the
- // deferred task will check the RxPacketQueue and send all packets on the
- // queue to the appropriate stream.
- //
- // Input:
- // member - contains information about the pci interrupt member
- // refCon - this value was passed in during the installation of the isr, since
- // we have globals we do not need to use this
- //
- // Output:
- // return kIsrIsComplete always
- //
- //-----------------------------------------------------------------------------------------
-
- InterruptMemberNumber ABCVendorISR(InterruptSetMember member, void *refCon, UInt32 theIntCount)
- {
- mblk_t *thePacket;
-
- OTEnterInterrupt(); // open transport needs to be notified when entering an interrupt
-
- // clear the bit that caused the interrupt
-
-
- // for the transmitter
- // is a packet waiting to be sent, then queue the deferred task
- if (gDLPIPrivateData->TxPacketQueue.qHead)
- OTScheduleDeferredTask(gDLPIPrivateData->TxDeferredTaskCookie);
-
-
- // for the receiver check if anything has come in
- // copy packet from hw into a message block then pass it on
-
- //if ((thePacket = allocb(the packet size), BPRI_HI))
- // {
-
- // copy packet into message block
- // bcopy(DMAPtrToPacket, thePacket->b_rptr, the packet size);
- // thePacket->b_wptr += the packet size;
- // Return the dma memory to the dma engine.
-
- // or you could use esballoc or OTAllocMsg which will use the DMAPtrToPacket
- // you will then get a callback when the client is finished with the dma memory
- // Keep in mind that packets could be returned via the callback out of order,
- // your dma hw might not be compatiable with this.
- //
- // put packet on the queue so callback routine can dequeue it and
- // pass it on to upper layers
- // EnqueueElement(&gDLPIPrivateData->RxPacketQueue,(QElem *)thePacket,kNoInterrupts);
- OTScheduleDeferredTask(gDLPIPrivateData->RxDeferredTaskCookie);
-
- // }
-
-
-
- OTLeaveInterrupt(); // open transport needs to be notified when leaving an interrupt
-
- return kIsrIsComplete;
- }
-
-